/*

    file:   window.c
    desc:   window tools implementation.

    author: Jaromir Dvorak (md@unicode.cz)

    This file is part of the AVGA platform.
    http://avga.prometheus4.com/
    

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
  
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
*/


#include <stdlib.h>
#include "window.h"
#include "../core/driver.h"
#include "misc.h"


unsigned char lastwindow = 0;
struct window windows[MAX_WINDOWS];

////
//Creates a window.
////
WINDOW window_add(unsigned char line, unsigned char height, unsigned char params)
{
	struct window* wnd = &windows[lastwindow];

	if(line > DRIVER_MAXY) return 0;
	if(line+height > DRIVER_MAXY) height = DRIVER_MAXY - line;

	wnd->line = line;
	wnd->height = height;
	wnd->params = params;

#ifdef WINDOW_INDIVIDUAL_TILESET
	wnd->pgmp = pgmpd;
#endif
#ifdef WINDOW_INDIVIDUAL_REFTABLE
	wnd->scrp = scrpd;
#endif


	if(++lastwindow >= MAX_WINDOWS) lastwindow=0;
	else
	{
		windows[lastwindow].height = 0;
		windows[lastwindow].params = 0;
	}

	return wnd;
}

////
//Resets to original state (maps whole default driver memory to whole screen)
////
void window_reset()
{
	lastwindow = 0;
	window_add(0, DRIVER_RESY > 255 ? 255 : DRIVER_RESY, 0xF8);
	window_select(windows);
	lastwindow = 0;
}


////
//Wait for a window to be scanned
////
#ifdef WINDOW_SYNC
void awindow_sync(WINDOW wnd)
{
	volatile extern WINDOW aw;
	volatile extern unsigned char wsync;

	wnd++;
	while(aw > wnd);
	wsync = 0;
	while(aw <= wnd && !wsync);
}
#endif


////
//Color masks.
////
void awindow_set_colormask(WINDOW wnd, unsigned char mask)
{
	register unsigned char tmp = wnd->params;
	tmp&=~0xF0;
	mask&=0xF0;
	tmp|=mask;
	wnd->params = tmp;
}


////
//Fast scrolling functions
////
static inline void awindow_set_scroll_x(WINDOW wnd, unsigned char x)
{
	register unsigned char tmp = wnd->params;
	tmp&=~7;
	x&=7;
	tmp|=x;
	wnd->params = tmp;
}
static inline signed char awindow_rel_scroll_x(WINDOW wnd, signed char x)
{
	register unsigned char xs = wnd->params;
	x+=xs&7;
	xs&=~7;
	xs|=x&7;
	wnd->params = xs;
	return x;
}


#if DRIVER_BLOCK_HEIGHT == 8
static inline void awindow_set_scroll_y(WINDOW wnd, unsigned char yp)
{
	register unsigned char tmp = wnd->line, y=yp;
	tmp&=~7; y&=7;	tmp|=y;
	wnd->line = tmp;
}
static inline signed char awindow_rel_scroll_y(WINDOW wnd, signed char yp)
{
	register unsigned char tmp = wnd->line, y=yp;
	y+=tmp&7; tmp&=~7; tmp|=y&7;
	return y;
}
#else
static inline void awindow_set_scroll_y(WINDOW wnd, unsigned char y)
{
	register unsigned char tmp = wnd->line;
	tmp -= DRIVER_Y2PRE(tmp); 
	y = DRIVER_Y2PRE(y);
	tmp += y;
	wnd->line = tmp;
}
static inline signed char awindow_rel_scroll_y(WINDOW wnd, signed char y)
{
	register unsigned char tmp = wnd->line;
	y += DRIVER_Y2PRE(tmp);
	tmp -= DRIVER_Y2PRE(tmp);
	tmp += DRIVER_Y2PRE(y);
	wnd->line = tmp;
	return y;
}
#endif


////
//Absolute scrolling (max. 7px vertically and 7px horizontally)
////
#if defined(HSCROLL) || defined(VSCROLL)
#ifdef WINDOW_ABS_SCROLL
void awindow_set_scroll(WINDOW wnd, unsigned char x, unsigned char y)
{
	awindow_set_scroll_x(wnd, x);
	awindow_set_scroll_y(wnd, y);
}
#endif


////
//Relative scrolling.
////
#ifdef WINDOW_SCROLL
void awindow_scroll(WINDOW wnd, signed char x, signed char y)
{
	awindow_rel_scroll_x(wnd, x);
	awindow_rel_scroll_y(wnd, y);
}
#endif

////
//Relative scrolling with data transfer.
////
#ifdef WINDOW_SCROLL_FULL
void awindow_scroll_full(WINDOW wnd, signed char x, signed char y, unsigned char default_block)
{
	x = awindow_rel_scroll_x(wnd, x) >> 3;
	y = awindow_rel_scroll_y(wnd, y) >> 3;
	
	signed char dir;
	if(y) dir = sgn(y);
	else if(x) dir = sgn(x);
	else return;


	register signed char xp = DRIVER_COLUMNS; 
	register signed char yp = window_get_height()+1;

	register unsigned char *scraddr1 = window_get_ptr();
	if(dir<0)  scraddr1 += (yp*DRIVER_COLUMNS-1);

	register unsigned char *scraddr2 = scraddr1;
	scraddr2+=x;
	scraddr2+=y*DRIVER_COLUMNS;

	x=abs(x);
	y=abs(y);

	while(1)
	{
		if(xp>x && yp>y) *scraddr1 = *scraddr2;
		else             *scraddr1 = default_block;

		scraddr1+=dir;
		scraddr2+=dir;

		if(!--xp) 
		{
			if(!--yp) return;
			xp=DRIVER_COLUMNS;
		}
	}
}
#endif
#endif










